#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
	@文件名	  :口型文本生成.py
	@时间	   :2024/5/27 上午2:34
	@作者	   :刘继泽
"""

import math
import select
import os
import shutil
import maya.cmds as cmds
import maya.mel as mel
import subprocess
import random


def asScriptLocatorProc ():
	pass


def asGetScriptLocation ():
	whatIs = mel.eval( 'whatIs asScriptLocatorProc' )
	fullPath = whatIs [25:]
	buffer = fullPath.split( "/" )
	numLetters = len( fullPath )
	numLettersLastFolder = len( buffer [-1] )
	scriptLocation = fullPath [0:(numLetters - numLettersLastFolder - 1)]
	return scriptLocation


def asEnsureAsGetScriptLocation ():
	asSelectorScriptLocation = ""
	AdvancedSkeletonMelFile = ""
	folders = []
	if "asGetScriptLocation" in globals():
		return
	elif "asSelectorScriptLocation" in globals():
		asSelectorScriptLocation = asSelectorScriptLocation
		if asSelectorScriptLocation.startswith( "/AdvancedSkeletonFiles/" ):
			AdvancedSkeletonMelFile = asStripPath( asSelectorScriptLocation , 2 ) + "AdvancedSkeleton.mel"
			if os.path.isfile( AdvancedSkeletonMelFile ):
				cmds.evalDeferred( '"source "'" + AdvancedSkeletonMelFile + "'' )
				print( "source "" + AdvancedSkeletonMelFile + "";\n" )
				cmds.error( "AdvancedSkeleton.mel was not sourced. Sourcing this now. Try running this function again" )
			else:
				cmds.error( "Expected file not found: " + AdvancedSkeletonMelFile )
		else:
			cmds.error( "Seems AdvancedSkeleton is not installed (only running Selector or Picker). This function requires AdvancedSkeleton installed.\n" )
	else:
		cmds.error( "Unable to run asGetScriptLocation, and unable to run asSelectorScriptLocation, so unable to determine directory for force-aligner." )


def asSelectorScriptLocation ():
	whatIs = mel.eval( 'whatIs asSelectorScriptLocation' )
	fullPath = whatIs [25:]
	buffer = fullPath.split( "/" )
	numTok = len( fullPath )
	print
	numTok
	if numTok < 2:
		if mel.eval( 'about -win' ):
			buffer = fullPath.split( "/" )
			print
			buffer
	numLetters = len( fullPath )
	numLettersLastFolder = len( buffer [-1] )
	scriptLocation = fullPath [:numLetters - numLettersLastFolder]
	return scriptLocation


def asAutoLipSyncLanguages ():
	languages = ["Bulgarian" , "Croatian" , "Czech" , "French" , "German" , "Hausa" , "Korean" , "Mandarin" , "Polish" , "Portuguese" , "Russian" , "Spanish" , "Swahili" , "Swedish" , "Thai" , "Turkish" , "Ukrainian" , "Vietnamese"]
	# languages=`stringArrayRemove {"Vietnamese"} $languages`;
	return languages


def currentTimeUnitToFPS ():
	unit = cmds.currentUnit( q = True , time = True )
	fps = 0

	if unit == "game":
		fps = 15
	elif unit == "film":
		fps = 24
	elif unit == "pal":
		fps = 25
	elif unit == "ntsc":
		fps = 30
	elif unit == "show":
		fps = 48
	elif unit == "palf":
		fps = 50
	elif unit == "ntscf":
		fps = 60
	elif unit == "2fps":
		fps = 2
	elif unit == "3fps":
		fps = 3
	elif unit == "4fps":
		fps = 4
	elif unit == "5fps":
		fps = 5
	elif unit == "6fps":
		fps = 6
	elif unit == "8fps":
		fps = 8
	elif unit == "10fps":
		fps = 10
	elif unit == "12fps":
		fps = 12
	elif unit == "16fps":
		fps = 16
	elif unit == "20fps":
		fps = 20
	elif unit == "23.976fps":
		fps = 24.0 * 1000.0 / 1001.0
	elif unit == "29.97fps":
		fps = 30.0 * 1000.0 / 1001.0
	elif unit == "29.97df":
		fps = 30.0 * 1000.0 / 1001.0
	elif unit == "40fps":
		fps = 40
	elif unit == "47.952fps":
		fps = 48.0 * 1000.0 / 1001.0
	elif unit == "59.94fps":
		fps = 60.0 * 1000.0 / 1001.0
	elif unit == "75fps":
		fps = 75
	elif unit == "80fps":
		fps = 80
	elif unit == "100fps":
		fps = 100
	elif unit == "120fps":
		fps = 120
	elif unit == "125fps":
		fps = 125
	elif unit == "150fps":
		fps = 150
	elif unit == "200fps":
		fps = 200
	elif unit == "240fps":
		fps = 240
	elif unit == "250fps":
		fps = 250
	elif unit == "300fps":
		fps = 300
	elif unit == "375fps":
		fps = 375
	elif unit == "400fps":
		fps = 400
	elif unit == "500fps":
		fps = 500
	elif unit == "600fps":
		fps = 600
	elif unit == "750fps":
		fps = 750
	elif unit == "1200fps":
		fps = 1200
	elif unit == "1500fps":
		fps = 1500
	elif unit == "2000fps":
		fps = 2000
	elif unit == "3000fps":
		fps = 3000
	elif unit == "6000fps":
		fps = 6000
	elif unit == "44100fps":
		fps = 41000
	elif unit == "48000fps":
		fps = 48000

	return fps


alignerDir = asGetScriptLocation() + "/AdvancedSkeletonFiles/bin/montreal-forced-aligner"
aligner = alignerDir + "/bin/mfa_align"
if mel.eval( 'about -win' ):
	aligner = alignerDir + "/bin/mfa_align.exe"
	print
	aligner
haveAligner = os.path.isfile( aligner )
languages = asAutoLipSyncLanguages


def asStripPath ( path , numStrip ):
	ret = ""
	tempString = []

	if path.startswith( "//" ):
		ret = "//"
	elif path.startswith( "/" ):
		ret = "/"

	tempString = path.split( "/" )
	for i in range( len( tempString ) - numStrip ):
		ret += tempString [i] + "/"

	return ret


def asGetTempDirectory ():
	tempDirectory = os.environ ['TEMP']
	folders = []
	if "~" in tempDirectory:
		folders = tempDirectory.split( "/" )
		tempDirectory = ""
		for i in range( len( folders ) ):
			if "~" in folders [i]:
				folders [i] = os.environ ['USERNAME']
			tempDirectory += folders [i]
			if i < len( folders ) - 1:
				tempDirectory += "/"
	return tempDirectory


def latinWriting ( language ):
	latin = 1
	# Bulgarian: Cyrillic alphabet
	# Korean: Hangul
	# Mandarin: Hanzi
	# Russian: Cyrillic alphabet
	# Thai: Thai script
	# Ukrainian: Cyrillic alphabet
	# Vietnamese: Vietnamese alphabet
	latinWritingLanguages = ["Bulgarian" , "Korean" , "Mandarin" , "Russian" , "Thai" , "Ukrainian" , "Vietnamese"]
	if language in latinWritingLanguages:
		latin = 0

	# Proceed with assuming all languages should be Romanized
	# latin = 1

	# checkBox can now choose this
	# print  cmds.checkBox ("asAutoLipSyncNonLatinCheckBox",q =1,label=1)
	# if not cmds.checkBox ("asAutoLipSyncNonLatinCheckBox",q =1,v=1):
	#	latin = 0

	return latin


def asAutoLipSyncForceAlign ( nameSpace ):
	segmentReplacing = 0
	# alwaysReCode = cmds.checkBox("asAutoLipSyncAlwaysReCodeCheckBox",q=True, v=1)#获取
	# print alwaysReCode
	aPlayBackSliderPython = mel.eval( '$tmpVar=$gPlayBackSlider' )  # 获取时间轴信息
	timeRangeArray = cmds.timeControl( aPlayBackSliderPython , q = True , rangeArray = 1 )
	print
	timeRangeArray
	if (timeRangeArray [1] - timeRangeArray [0]) > 1:
		segmentReplacing = 1
	print
	segmentReplacing
	fps = currentTimeUnitToFPS()  # 帧速率
	if fps < 1:
		fps = 1  # nameSpace = asNameSpaceFromUIName(input_string)#名字空间
	mfaDir = ''
	cmd = ''
	genDictCmd = ''
	ffMpegCmd = ''
	pythonCmd = ''
	uniDecoded = ""
	tempString = []
	# languageMenuValue = cmds.optionMenu("asAutoLipSyncLanguageOptionMenu",q=True, v=1)
	# print languageMenuValue,"8888888888888888888"
	language = "english"  # 转成小写
	aligner = "C:/Users/pc/Downloads/AdvancedSkeleton/AdvancedSkeletonFiles/bin/montreal-forced-aligner/bin/mfa_align.exe"  # cmds.text("asAutoLipSyncAlignerText",q=True, l=1)

	mfaDir = asStripPath( aligner , 2 )
	lexicon = mfaDir + "bin/librispeech-lexicon.txt"

	ffmpeg = mfaDir + "bin/ffmpeg.e"

	if mel.eval( "about -mac" ):
		ffmpeg = mfaDir + "bin/ffmpeg"

	mfaGD = mfaDir + "bin/mfa_generate_dictionary"
	g2pFile = mfaDir + "pretrained_models/" + language + "_g2p.zip"
	languageZipFile = mfaDir + "pretrained_models/" + language + ".zip"  # 语言模型路径
	tempDir = asGetTempDirectory() + "/AdvancedSkeleton/autoLipSync/"  # 获取本地缓存路径
	audioNode = cmds.timeControl( aPlayBackSliderPython , q = True , s = 1 )  # 获取时间轴的音频

	if not cmds.objExists( audioNode ):
		cmds.error( "No sound found. Make sure to import a sound file first" )

	soundFile = cmds.getAttr( audioNode + ".filename" )
	tempString = soundFile.split( "/" )
	soundFileBaseName = tempString [len( tempString ) - 1]  # 音频文件
	tempString = soundFile.split( "." )
	soundFileExt = tempString [len( tempString ) - 1]
	forceSoundFile = tempDir + "input/align." + soundFileExt
	forceTextFile = tempDir + "input/align.txt"
	textGridFile = tempDir + "output/align.TextGrid"
	forceText = "z b S L B J T W L S Zu T D L B T T Z D G Z L D S C Y L D Y L J S Z T H"  # cmds.scrollField("asAutoLipSyncUIScrollField",q=True, tx=1 )

	if not cmds.objExists( nameSpace + "FaceControlSet" ):
		cmds.error( u"未检测到控制集。选择控制器" )

	if not cmds.objExists( nameSpace + "ctrlPhonemes_M" ):
		cmds.error( nameSpace + "ctrlPhonemes_M not found" )

	if not cmds.file( aligner , q = True , ex = 1 ):
		cmds.error( u"缺少文件:\"" + aligner + "\"" )
	genDictCmd = ''
	if language != "english":
		lexicon = tempDir + "sessionLexicon.txt"
		if (mel.eval( "about -mac" )) or (mel.eval( "about -linux" )):
			print( "11111111111" )
			genDictCmd = "\"" + mfaGD + "\" \"" + g2pFile + "\" \"" + tempDir + "input/\" \"" + lexicon + "\""
		else:
			print( "2222222222" )
			genDictCmd = "start/wait/I \"Generating Dictionary\" \"" + mfaGD + "\" \"" + g2pFile + "\" \"" + tempDir + "input/\" \"" + lexicon + "\""
	# print lexicon
	# print genDictCmd

	if (mel.eval( "about -mac" )) or (mel.eval( "about -linux" )):
		cmd = aligner + " -c " + tempDir + "input\\" + lexicon + language + tempDir + "output\\"
		ffMpegCmd = "start/wait/I Coding Audio" + ffmpeg + " -y -i " + soundFile
	else:
		cmd = 'start/wait/I "Force Aligning:" "%s" -c "%sinput/" "%s" %s "%soutput/"' % (aligner.replace( "\\" , "/" ) , tempDir.replace( "\\" , "/" ) , lexicon.replace( "\\" , "/" ) , language , tempDir.replace( "\\" , "/" ))
		ffMpegCmd = 'start/wait/I "Coding Audio" "%s" -y -i "%s"' % (ffmpeg.replace( "\\" , "/" ) , soundFile.replace( "\\" , "/" ))
		print
		cmd
		print
		ffMpegCmd  # / Starting Force Aligning:start/wait/I "Force Aligning" "C:/Users/pc/Downloads/AdvancedSkeleton/AdvancedSkeletonFiles/bin/montreal-forced-aligner/bin/mfa_align.exe" -c "C:/Users/pc/AppData/Local/Temp/AdvancedSkeleton/autoLipSync/input/" "C:/Users/pc/Downloads/AdvancedSkeleton/AdvancedSkeletonFiles/bin/montreal-forced-aligner/bin/librispeech-lexicon.txt" english "C:/Users/pc/AppData/Local/Temp/AdvancedSkeleton/autoLipSync/output/"  # // Successfully created:"C:/Users/pc/AppData/Local/Temp/AdvancedSkeleton/autoLipSync/output/align.TextGrid".
	if not os.path.exists( soundFile ):
		cmds.error( u"不是有效的声音文件" )
	if os.path.exists( tempDir + "output" ):
		tempString = os.listdir( tempDir + "output" )
		for file in tempString:
			os.remove( tempDir + "output/" + file )

	if "asAutoLipSyncNonLatinCheckBox" and not segmentReplacing:
		if os.path.exists( tempDir + "render" ):
			tempString = os.listdir( tempDir + "render" )
			for file in tempString:
				os.remove( tempDir + "render/" + file )

	if not os.path.exists( tempDir + "input" ):
		os.makedirs( tempDir + "input" )
	if not os.path.exists( tempDir + "output" ):
		os.makedirs( tempDir + "output" )
		os.shutil.copy( forceSoundFile , soundFile )
	# if segmentReplacing or alwaysReCode:
	#	if not os.path.exists(ffmpeg):
	#		asAutoLipSyncFfmpegDownload()
	if segmentReplacing:
		print( u"//在时间线滑块上找到分段选择，将音频修剪到所选内容.\n" )
		ffMpegCmd += " -ss " + (timeRangeArray [0] / fps) + " -to " + (timeRangeArray [1] / fps) + " " + forceSoundFile
		print( u"// 开始修剪音频:" + ffMpegCmd + "\n" )
		os.system( ffMpegCmd )
	# if alwaysReCode:
	ffMpegCmd += " " + forceSoundFile
	print( u"// 启动ReCode Audio:" + ffMpegCmd + "\n" )
	os.system( ffMpegCmd )
	print( ffMpegCmd , "0000000000000000000000000000000000000000000000000000000000" )

	import unicodedata
	# print (latinWriting(languageMenuValue),languageMenuValue)
	# def latinWriting(languageMenuValue, forceText, forceTextFile, asAutoLipSyncUIScrollField):
	if latinWriting( "english" ):
		# Unidecode to transliterates any unicode string into the closest possible representation in ascii text.
		# open file > strip_accents > save file, in Py, so we do not need to pass the text as variable
		print( forceText )
		forceText = forceText.replace( "`" , "" )
		forceText = forceText.replace( "'" , " " )
		forceText = forceText.replace( "\n" , " " )

		def strip_accents ( s ):
			print( "-----------------------------" )
			return ''.join( c for c in unicodedata.normalize( 'NFD' , s ) if unicodedata.category( c ) != 'Mn' )

		# uniDecoded = strip_accents(forceText)
		print
		uniDecoded
		with open( forceTextFile , "w" ) as file:
			file.write( forceText )

	# if uniDecoded != forceText:  #	cmds.scrollField("asAutoLipSyncUIScrollField",e=True, tx=uniDecoded)

	if language != "english":
		print( u"// 正在启动生成词典:" + genDictCmd + "\n" )
		if os.path.exists( lexicon ):
			cmds.sysFile( lexiconde , l = 1 )
		os.system( genDictCmd )
		if not os.path.exists( lexicon ):
			cmds.error( u"创建词典失败:" + lexicon )
	print( forceText )
	if forceText != "":
		print( u"// Starting Force Aligning" + cmd + "\n" )
		os.system( cmd )
	else:
		with open( textGridFile , "w" ) as file:
			fileId = file.read()
			print( fileId )

	if os.path.exists( textGridFile ):
		print( "// 已成功创建:" + textGridFile + ".\n" )
	else:
		if os.path.exists( tempDir + "output/unaligned.txt" ):
			with open( fileId , "r" ) as file:
				tempString = file.read()
				print( tempString + "\n" )

		if cmds.confirmDialog( title = "Confirm" , message = "强制对齐失败。\n这可能是声音文件的兼容性问题。\n是否尝试重新编码声音文件？" , button = ["Yes" , "No"] , defaultButton = "Yes" , cancelButton = "No" , dismissString = "No" ) == "Yes":
			cmds.checkBox( "asAutoLipSyncAlwaysReCodeCheckBox" , e = True , v = 1 )
			asAutoLipSyncForceAlign( nameSpace )
			return

			# asAutoLipSyncLanguageChanged()
			# asAutoLipSyncForceAlign(nameSpace)
			return
		cmds.error( "创建失败:\"" + textGridFile + ".\n" )

	asAutoLipSyncImport( nameSpace )


def asGetImConvertCmd ():
	imConvertCmd = "imconvert"
	mayaLocation = os.getenv( "MAYA_LOCATION" )
	print( mayaLocation )
	print( os.path.exists( mayaLocation + "/bin/magick.exe" ) )
	print( os.path.exists( mayaLocation + "/bin/magick" ) )
	if os.path.exists( mayaLocation + "/bin/magick.exe" ) or os.path.exists( mayaLocation + "/bin/magick" ):
		imConvertCmd = "magick"
	print( imConvertCmd )
	return imConvertCmd


def asAutoLipSyncImport ( nameSpace ):
	nameSpace = "A10_C0350WJY_RIG:"
	gMainProgressBar = mel.eval( '$tmpVar=$gMainProgressBar' )
	gPlayBackSlider = "PlayBackSlider"
	gCurrentTimeCmdValueTable = []
	segmentReplacing = 0
	aPlayBackSliderPython = mel.eval( '$tmpVar=$gPlayBackSlider' )  # 获取时间轴信息
	timeRangeArray = cmds.timeControl( aPlayBackSliderPython , q = True , rangeArray = 1 )
	fps = currentTimeUnitToFPS()
	if fps < 1:
		fps = 1
	# 外部文本开关
	# nonLatin = cmds.checkBox("asAutoLipSyncNonLatinCheckBox" , q = True , v = 1)  # non-latin alphabet
	# print cmds.checkBox("asAutoLipSyncNonLatinCheckBox" , q = True , l = 1) ,"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}"
	wordsSection , phonesSection , fileId = 0 , 0 , 0
	'''
	autoBlink = cmds.checkBox("asAutoLipSyncBlinkCheckBox" , q = True , v = 1)  # True
	autoGlimpse = cmds.checkBox("asAutoLipSyncGlimpseCheckBox" , q = True , v = 1)  # True
	autoEyeBrows = cmds.checkBox("asAutoLipSyncEyeBrowsCheckBox" , q = True , v = 1)  # True
	autoHead = cmds.checkBox("asAutoLipSyncHeadCheckBox" , q = True , v = 1)  # True
	'''
	lastKeyFrameNr , nextBlinkTriggFrameNr , nextGlipseTriggFrameNr , nextHeadTriggFrameNr , wordNr = 0 , 0 , 0 , 0 , 0
	if not cmds.objExists( nameSpace + "FKHead_M" ):
		autoHead = 0
	prePhoneTime = 0.01 * fps  # cmds.floatField("asAutoLipSyncPhonemeInFloatField" , q = True , v = 1)
	postPhoneTime = 0.01 * fps  # cmds.floatField("asAutoLipSyncPhonemeOutFloatField" , q = True , v = 1)
	sequenceStart = -1
	sequenceEnd = -1
	wordSpace = 0.25  # 0.25*$fps
	scale = 1.5
	xMin , xMax , segRepOffset , keyValue , previousKeyTime = 0 , 0 , 0 , 0 , 0
	wordStarts , wordEnds , phoneStarts , phoneEnds , bb , keyTimes , pos , pos1 , pos2 = [] , [] , [] , [] , [] , [] , [] , [] , []
	aligner = "C:/Users/pc/Downloads/AdvancedSkeleton/AdvancedSkeletonFiles/bin/montreal-forced-aligner/bin/mfa_align.exe"  # cmds.text("asAutoLipSyncAlignerText" , q = True , l = 1)
	tempDir = asGetTempDirectory() + "/AdvancedSkeleton/autoLipSync/"
	textGridFile = tempDir + "output/align.TextGrid"
	nextLine , para , value , pythonCmd , fileRead , font , imConvertCmdLine = "" , "" , "" , "" , "" , "" , ""
	imConvertCmd = asGetImConvertCmd()
	tempString , words , phones , missingPhoneParts , letters , deleteObjs , texts , chars = [] , [] , [] , [] , [] , [] , [] , []
	currentTimeUnit = cmds.currentUnit( q = True , t = True )
	audioNode = cmds.timeControl( aPlayBackSliderPython , q = True , s = 1 )
	# languageMenuValue = cmds.optionMenu("asAutoLipSyncLanguageOptionMenu" , q = True , v = 1)
	language = "english"  # languageMenuValue.lower()
	offset = cmds.getAttr( audioNode + ".offset" ) / fps

	if not cmds.objExists( nameSpace + "ctrlPhonemes_M" ):
		cmds.error( nameSpace + "ctrlPhonemes_M not found" )

	if cmds.objExists( nameSpace + "FaceFitSkeletonHeightShape" ):
		pos1 = cmds.xform( nameSpace + "FaceFitSkeletonHeightShape.cv[5]" , q = True , ws = True , t = 1 )
		pos2 = cmds.xform( nameSpace + "FaceFitSkeletonShape.cv[5]" , q = True , ws = True , t = 1 )
		scale = pos1 [1] - pos2 [1]

	if (timeRangeArray [1] - timeRangeArray [0]) > 1 and cmds.objExists( nameSpace + "subTitles" ):
		segmentReplacing = 1

	if segmentReplacing:
		cmds.select( cl = True )
		pos = cmds.xform( nameSpace + "subTitlesArrowShape.cv[3]" , q = True , ws = True , t = 1 )
		texts = cmds.listRelatives( nameSpace + "subTitlesRoller" , c = 1 , type = "transform" )
		cmds.currentTime( timeRangeArray [0] )
		previousKeyTime = cmds.findKeyframe( nameSpace + "subTitlesRoller.tx" , q = 1 , which = "previous" , time = 1 )

		for i in range( len( texts ) ):
			chars = cmds.listRelatives( c = True , type = "transform" , ad = True , f = texts [i] )
			print( chars )
			'''
			if nonLatin:
				chars[0] = texts[i]
				'''
			for y in range( len( chars ) ):
				if (cmds.getAttr( t = (cmds.getAttr( previousKeyTime , (nameSpace + "subTitlesRoller.tx") ) * -1 , cmds.getAttr( (texts [i] + ".tx") )) )):
					cmds.select( add = True , objects = texts [i] )
					print( ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;" )

		if len( cmds.ls( selection = True ) ) > 0:
			cmds.delete()

		if cmds.objExists( nameSpace + "subTitlesRoller" ):
			cmds.cutKey( time = (timeRangeArray [0] + ":99999") , attribute = "translateX" , option = "keys" , clear = True )
		cmds.cutKey( time = (timeRangeArray [0] + ":99999") , option = "keys" , clear = True , attribute = (nameSpace + "ctrlPhonemes_M") )

	# if not mel.eval('stringArrayCount("sec", %s)'%(gCurrentTimeCmdValueTable)) and mel.eval('exists( workingTimeUtil)'):
	#	cmds.optionVar(iv=("hideNoFPSFramerate", 0))
	#	cmds.evalDeferred("source workingTimeUtil")

	cmds.currentUnit( t = "sec" )
	# cmds.evalDeferred('catchQuiet(\'currentUnit -t {}\')'.format(currentTimeUnit))

	if cmds.currentUnit( q = True , t = True ) == "sec":
		cmds.currentUnit( t = "film" )
	if segmentReplacing:
		segRepOffset = cmds.currentTime( q = 1 )
	if segmentReplacing:
		if cmds.objExists( "subTitles_parentConstraint1" ):
			cmds.delete( "subTitles_parentConstraint1" )
		if cmds.objExists( nameSpace + "subTitles" ):
			cmds.xform( ws = True , t = [0 , 0 , 0] , ro = [0 , 0 , 0] , s = [1 , 1 , 1] , object = (nameSpace + "subTitles") )
	else:
		deleteObjs = [nameSpace + "subTitles" , nameSpace + "subTitlesExp" , nameSpace + "subTitlesBox" , nameSpace + "subTitlesArrow" , nameSpace + "subTitlesBoxMPD"]
		for i in range( len( deleteObjs ) ):
			if cmds.objExists( deleteObjs [i] ):
				cmds.delete( deleteObjs [i] )
		cmds.createNode( "transform" , name = nameSpace + "subTitles" )  # createNode -n ($nameSpace+"subTitles") transform;
		cmds.createNode( "transform" , name = nameSpace + "subTitlesRoller" , parent = nameSpace + "subTitles" )  # createNode -n ($nameSpace+"subTitlesRoller") -p ($nameSpace+"subTitles") transform;
		tempString = cmds.curve( d = 1 , p = [(-4 , 1.25 , 0) , (-4 , -0.5 , 0) , (4 , -0.5 , 0) , (4 , 1.25 , 0) , (-4 , 1.25 , 0)] , k = [0 , 1 , 2 , 3 , 4] )  # $tempString[0]=`curve -d 1 -p -4 1.25 0 -p -4 -0.5 0 -p 4 -0.5 0 -p 4 1.25 0 -p -4 1.25 0 -k 0 -k 1 -k 2 -k 3 -k 4`;
		cmds.rename( tempString , nameSpace + "subTitlesBox" )  # rename $tempString[0] ($nameSpace+"subTitlesBox");
		cmds.setAttr( nameSpace + "subTitlesBoxShape.overrideEnabled" , 1 )  # setAttr ($nameSpace+"subTitlesBoxShape.overrideEnabled") 1;
		cmds.setAttr( nameSpace + "subTitlesBoxShape.overrideColor" , 13 )
		tempString = cmds.curve( d = 1 , p = [(0 , 0.65 , 0) , (0.127 , 1.2 , 0) , (-0.127 , 1.2 , 0) , (0 , 0.65 , 0)] , k = [0 , 1 , 2 , 3] )  # $tempString[0]=`curve -d 1 -p 0 0.65 0 -p 0.127 1.2 0 -p -0.127 1.2 0 -p 0 0.65 0 -k 0 -k 1 -k 2 -k 3`;
		cmds.parent( nameSpace + "subTitlesBox" , nameSpace + "subTitles" )  # parent ($nameSpace+"subTitlesBox") ($nameSpace+"subTitles");
		cmds.addAttr( nameSpace + "subTitlesBox" , k = 1 , ln = "textVisCenter" , at = "double" , dv = 4.5 )  # addAttr -k 1 -ln textVisCenter -at double -dv 4.5 ($nameSpace+"subTitlesBox");
		cmds.addAttr( nameSpace + "subTitlesBox" , k = 1 , ln = "textVisLenght" , at = "double" , dv = 8 )  # addAttr -k 1 -ln textVisLenght -at double -dv 8 ($nameSpace+"subTitlesBox");
		cmds.createNode( "multiplyDivide" , n = nameSpace + "subTitlesBoxMPD" )  # createNode -n ($nameSpace+"subTitlesBoxMPD") multiplyDivide;
		cmds.connectAttr( nameSpace + "subTitlesBox.sx" , nameSpace + "subTitlesBoxMPD.input1X" )  # connectAttr ($nameSpace+"subTitlesBox.sx") ($nameSpace+"subTitlesBoxMPD.input1X");
		cmds.connectAttr( nameSpace + "subTitlesBox.sx" , nameSpace + "subTitlesBoxMPD.input1Y" )  # connectAttr ($nameSpace+"subTitlesBox.sx") ($nameSpace+"subTitlesBoxMPD.input1Y");
		cmds.setAttr( nameSpace + "subTitlesBoxMPD.input2" , 4 , 8 , 0 , type = "float3" )  # setAttr ($nameSpace+"subTitlesBoxMPD.input2") -type float3 4 8 0;
		cmds.connectAttr( nameSpace + "subTitlesBoxMPD.outputX" , nameSpace + "subTitlesBox.textVisCenter" )  # connectAttr ($nameSpace+"subTitlesBoxMPD.outputX") ($nameSpace+"subTitlesBox.textVisCenter");
		cmds.connectAttr( nameSpace + "subTitlesBoxMPD.outputY" , nameSpace + "subTitlesBox.textVisLenght" )  # connectAttr ($nameSpace+"subTitlesBoxMPD.outputY") ($nameSpace+"subTitlesBox.textVisLenght");
		cmds.rename( tempString , nameSpace + "subTitlesArrow" )  # rename $tempString[0] ($nameSpace+"subTitlesArrow");
		cmds.setAttr( nameSpace + "subTitlesArrowShape.overrideEnabled" , 1 )  # setAttr ($nameSpace+"subTitlesArrowShape.overrideEnabled") 1;
		cmds.setAttr( nameSpace + "subTitlesArrowShape.overrideColor" , 13 )  # setAttr ($nameSpace+"subTitlesArrowShape.overrideColor") 13;
		cmds.parent( nameSpace + "subTitlesArrowShape" , nameSpace + "subTitlesBox" , add = 1 , s = 1 )  # parent -add -s ($nameSpace+"subTitlesArrowShape") ($nameSpace+"subTitlesBox");
		cmds.delete( nameSpace + "subTitlesArrow" )  # delete ($nameSpace+"subTitlesArrow");
		tempString = cmds.listConnections( nameSpace + "ctrlPhonemes_M" , s = 1 , d = 0 , type = "animCurve" )  # $tempString=`listConnections -s 1 -d 0 -type animCurve ($nameSpace+"ctrlPhonemes_M")`;
		print( tempString )
		# cmds.parentConstraint(nameSpace + "ctrlBox" , nameSpace + "subTitlesRoller" , mo = True)
		if tempString:  # if (size($tempString)) delete $tempString;
			cmds.delete( tempString )

			tempString = cmds.listAttr( nameSpace + "ctrlPhonemes_M" , ud = True )
			for attr in tempString:
				if not cmds.getAttr( nameSpace + "ctrlPhonemes_M." + attr , lock = True ):
					cmds.setAttr( nameSpace + "ctrlPhonemes_M." + attr , 0 )
			if cmds.attributeQuery( "jaw" , node = nameSpace + "ctrlPhonemes_M" , exists = True ):
				cmds.setAttr( nameSpace + "ctrlPhonemes_M.jaw" , 0.25 )
				cmds.setAttr( nameSpace + "ctrlPhonemes_M.lip" , 0.25 )
				if cmds.objExists( "asFaceBS" ):
					cmds.setAttr( nameSpace + "ctrlPhonemes_M.jaw" , 1 )
					cmds.setAttr( nameSpace + "ctrlPhonemes_M.lip" , 1 )
	print( textGridFile )

	with open( textGridFile , 'r' ) as fileId:
		for nextLine in fileId:
			line = nextLine.strip()
			if line:
				tempString = line.split( " = " )
				if len( tempString ) >= 2:
					para = tempString [0]
					value = tempString [1]
					# print(para)
					# print(value)

					if sequenceStart == -1 and para == "xmin":
						sequenceStart = float( value ) * fps

					if sequenceEnd == -1 and para == "xmax":
						sequenceEnd = float( value ) * fps

					if para == "name":
						if value == "\"words\"":
							wordsSection = 1
						if value == "\"phones\"":
							phonesSection = 1
							wordsSection = 0

					if para == "xmin":
						xMin = float( value )
					if para == "xmax":
						xMax = float( value )

					if wordsSection and para == "text":
						tempString [0] = value.replace( "\"" , "" )
						if tempString [0] != "":
							words.append( tempString [0] )
							wordStarts.append( (xMin + segRepOffset + offset) * fps )
							wordEnds.append( (xMax + segRepOffset + offset) * fps )

					if phonesSection and para == "text":
						tempString [0] = value.replace( "\"" , "" )
						if tempString [0] != "":
							phones.append( tempString [0] )
							phoneStarts.append( (xMin + segRepOffset + offset) * fps )
							phoneEnds.append( (xMax + segRepOffset + offset) * fps )

	fileId.close()

	for i in range( len( words ) ):
		if words [i] == "<unk>":
			words [i] = "***"
	if not segmentReplacing:
		cmds.playbackOptions( min = (sequenceStart + offset) , ast = (sequenceStart + offset) , aet = (sequenceEnd + offset) , max = (sequenceEnd + offset) )

	# setKeyframe command
	cmds.setKeyframe( nameSpace + "subTitlesRoller" , at = "tx" , v = 0 , t = 0 , itt = "linear" , ott = "linear" )

	# for loop
	wordNr = 0
	for i in range( 9999 ):
		if not cmds.objExists( nameSpace + "text" + str( i ) ):
			break
		wordNr = i
	# 外部文档打开后
	'''
	if nonLatin:
		if not os.path.exists(tempDir + "render"):
			os.makedirs(tempDir + "render")
		wordsSection = 0
		# wordNr = wordNr
		searchfile = open(textGridFile , 'r')
		for line in searchfile:
			if line.find('name = \"words\"') != -1:
				wordsSection = 1
			if line.find('name = \"phones\"') != -1:
				wordsSection = 0
			if wordsSection == 1:
				if line.find('text = ') != -1:
					word = line.split()[2].replace('\"' , '')
					if word == '':
						continue
					tempDir + "render/word" + str(wordNr) + ".txt"
					wordFile = open(tempDir + "render/word" + str(wordNr) + ".txt" , 'w')
					wordFile.write(word)
					wordFile.close()
					wordNr = wordNr + 1
		searchfile.close()

	if nonLatin:
		cmds.progressBar(gMainProgressBar , e = True , ep = 1)
	'''
	cmds.progressBar( gMainProgressBar , e = True , st = "Reading Data" , bp = 1 , ii = 1 , min = 0 , max = (len( words ) + 1) )
	for i in range( len( words ) ):
		cmds.progressBar( gMainProgressBar , e = True , s = 1 )
		if cmds.progressBar( gMainProgressBar , q = True , ic = 1 ):
			cmds.error( "Interrupted" )
		cmds.currentTime( wordStarts [i] )
		'''
		if nonLatin:
			font = "arial"
		'''
		if language == "thai":
			font = "tahoma"
		if language == "korean":
			font = "Malgun-Gothic"
		imConvertCmdLine = imConvertCmd + " -background black -fill white -font " + font + " -pointsize 72 label:@" + tempDir + "render/word" + str( wordNr ) + ".txt " + tempDir + "render/word" + str( wordNr ) + ".png"
		subprocess.call( imConvertCmdLine , shell = True )
		# mel.eval('system(%s)'%imConvertCmdLine)
		tempString = cmds.ls( (nameSpace + "text*" + str( wordNr )) )
		for y in range( len( tempString ) ):
			if cmds.objExists( tempString [y] ):
				cmds.delete( tempString [y] )
			cmds.polyPlane( n = nameSpace + "text" + str( wordNr ) , w = 1 , h = 1 , sx = 1 , sy = 1 , ax = [0 , 0 , 1] , cuv = 2 , ch = 0 )
			cmds.shadingNode( "surfaceShader" , n = nameSpace + "textShader" + str( wordNr ) , asShader = 1 )
			cmds.sets( renderable = True , noSurfaceShader = True , empty = True , name = (nameSpace + "textSG" + str( wordNr )) )
			cmds.connectAttr( nameSpace + "textShader" + str( wordNr ) + ".outColor" , nameSpace + "textSG" + str( wordNr ) + ".surfaceShader" , f = 1 )
			cmds.sets( nameSpace + "text" + str( wordNr ) , e = True , forceElement = nameSpace + "textSG" + str( wordNr ) )
			cmds.createNode( "file" , n = nameSpace + "textFile" + str( wordNr ) )
			cmds.connectAttr( nameSpace + "textFile" + str( wordNr ) + ".outColor" , nameSpace + "textShader" + str( wordNr ) + ".outColor" , force = 1 )
			cmds.setAttr( (nameSpace + "textFile" + str( wordNr ) + ".fileTextureName") , (tempDir + "render/word" + str( wordNr ) + ".png") , type = "string" )
			cmds.move( 0.5 , 0 , 0 , nameSpace + "text" + str( wordNr ) + ".vtx[0:99]" , r = True , ws = True , wd = 1 )
			cmds.scale( len( words [i] ) / 2.25 , 1 , 1 , nameSpace + "text" + str( wordNr ) + ".vtx[0:99]" , r = True , p = [0 , 0 , 0] )
		else:
			tempString = cmds.textCurves( f = "Times New Roman|wt:50|sz:28" , t = words [i] )
			cmds.delete( cmds.ls( type = "makeTextCurves" ) )
			cmds.rename( tempString [0] , nameSpace + "text" + str( wordNr ) )
		cmds.setAttr( nameSpace + "text" + str( wordNr ) + ".tx" , wordSpace )
		cmds.parent( nameSpace + "text" + str( wordNr ) , nameSpace + "subTitlesRoller" )
		cmds.setKeyframe( nameSpace + "subTitlesRoller.tx" , itt = "linear" , ott = "linear" , t = wordStarts [i] , v = (cmds.getAttr( (nameSpace + "subTitlesRoller.tx") ) - wordSpace) )
		bb = cmds.xform( nameSpace + "text" + str( wordNr ) , q = 1 , ws = 1 , bb = 1 )
		keyValue = cmds.getAttr( nameSpace + "subTitlesRoller.tx" ) - (float( bb [0] ) + float( bb [3] ))
		cmds.setKeyframe( nameSpace + "subTitlesRoller.tx" , itt = "linear" , ott = "linear" , t = wordEnds [i] , v = keyValue )
		wordNr += 1
	for i in range( len( phones ) ):
		if (phones [i] == "sil" or phones [i] == "sp" or phones [i] == "spn"):
			continue
		# if (language == "english"):
		phoneme = asAutoLipSyncPhonemeMapping( phones [i] )
		# else:
		#	 phoneme = substring(language, 0, 3) + "_" + asPhonemeTranslate(phones[i], 0)
		if phoneme == "" or not cmds.attributeQuery( phoneme , n = nameSpace + "ctrlPhonemes_M" , exists = True ):
			if not phoneme in missingPhoneParts:
				missingPhoneParts.append( "Phoneme:\"" + phoneme + "\", from the phone:	\"" + phones [i] + "\"" )
			continue
		cmds.setKeyframe( nameSpace + "ctrlPhonemes_M." + phoneme , v = 0 , t = (phoneStarts [i] - prePhoneTime) )
		# print(phoneStarts [i] - prePhoneTime)
		cmds.setKeyframe( nameSpace + "ctrlPhonemes_M." + phoneme , v = 10 , t = ((phoneStarts [i] + phoneEnds [i]) / 2) )
		# print ((phoneStarts [i] + phoneEnds [i]) / 2.0)
		cmds.setKeyframe( nameSpace + "ctrlPhonemes_M." + phoneme , v = 0 , t = (phoneEnds [i] + postPhoneTime) )
	# print(phoneEnds [i] + postPhoneTime)

	if len( missingPhoneParts ) > 0:
		print( "Found the following phonemes, that are not mapped to the current FaceSetup:" )
	# print( missingPhoneParts )
	cmds.progressBar( gMainProgressBar , e = True , ep = 1 )
	cmds.currentTime( 0 )

	cmds.currentTime( 0 )
	tempString = cmds.listRelatives( nameSpace + "subTitlesRoller" , ad = True , type = "transform" , f = 1 )
	for i in range( len( tempString ) ):
		if not tempString [i].startswith( "Char_" ):  # and not nonLatin
			continue
		letters.append( tempString [i] )

	bb = cmds.xform( nameSpace + "subTitlesBox" , q = True , ws = True , bb = 1 )
	boxWidth = (bb [3] - bb [0]) / cmds.getAttr( nameSpace + "subTitles.sx" )

	if nameSpace != "" and cmds.objExists( "subTitlesRoller_translateX" ):
		cmds.rename( "subTitlesRoller_translateX" , nameSpace + "subTitlesRoller_translateX" )

	keyTimes = cmds.keyframe( nameSpace + "subTitlesRoller_translateX" , q = True , tc = 1 )
	lastKeyFrameNr = keyTimes [-1]
	cmds.progressBar( gMainProgressBar , e = True , st = "Animating text visibility" , bp = True , min = 0 , max = lastKeyFrameNr + 1 )

	for y in range( len( letters ) ):
		if cmds.objExists( (letters [y] + "PMA") ):
			continue
		cmds.createNode( "plusMinusAverage" , n = (letters [y] + "PMA") )
		cmds.connectAttr( nameSpace + "subTitlesRoller_translateX.output" , letters [y] + "PMA.input1D[1]" , f = True )
		cmds.connectAttr( nameSpace + "subTitlesBox.textVisCenter" , letters [y] + "PMA.input1D[2]" , f = True )
		bb = cmds.xform( q = True , ws = True , bb = letters [y] )
		cmds.setAttr( letters [y] + "PMA.input1D[0]" , bb [0] + 0.5 )
		cmds.createNode( "clamp" , n = letters [y] + "Clamp" )
		cmds.connectAttr( letters [y] + "PMA.output1D" , letters [y] + "Clamp.inputR" , f = True )
		cmds.setAttr( letters [y] + "Clamp.maxR" , 1000 )
		cmds.createNode( "condition" , n = letters [y] + "Condition" )
		cmds.setAttr( letters [y] + "Condition.operation" , 2 )
		cmds.connectAttr( letters [y] + "Clamp.outputR" , letters [y] + "Condition.firstTerm" , f = True )
		cmds.connectAttr( letters [y] + "Clamp.outputR" , letters [y] + "Condition.colorIfFalseR" , f = True )
		cmds.connectAttr( nameSpace + "subTitlesBox.textVisLenght" , letters [y] + "Condition.secondTerm" , f = True )
		cmds.connectAttr( letters [y] + "Condition.outColorR" , letters [y] + ".v" , f = True )

	# 字幕对齐到头部
	bb = cmds.xform( nameSpace + "subTitles" , q = True , ws = True , bb = 1 )
	cmds.setAttr( (nameSpace + "subTitles.s") , scale / 10.0 , scale / 10.0 , scale / 10.0 , type = "float3" )
	bb = cmds.xform( nameSpace + "ctrlBox" , q = True , ws = True , bb = 1 )
	bb2 = cmds.xform( nameSpace + "ctrlPhonemes_M" , q = True , ws = True , bb = 1 )
	bb3 = cmds.xform( nameSpace + "subTitlesBox" , q = True , ws = True , bb = 1 )
	cmds.xform( nameSpace + "subTitles" , ws = True , t = [bb [3] + bb3 [3] * 1.2 , bb2 [1] , bb [5]] )
	cmds.parentConstraint( nameSpace + "ctrlBox" , nameSpace + "subTitles" , mo = True )

	if segmentReplacing:
		cmds.select( r = (nameSpace + "subTitles") )
		cmds.currentTime( timeRangeArray [0] )
		cmds.dgdirty( a = True )
	# 自动眨眼转头
	# if autoBlink:
	tempString = cmds.listConnections( nameSpace + "ctrlEye_R" , nameSpace + "ctrlEye_L" , s = True , d = False , type = "animCurve" , shapes = True )
	if (tempString):
		cmds.delete( tempString )
	# 视线
	# if autoGlimpse:
	tempString = cmds.listConnections( nameSpace + "Eye_R" , nameSpace + "Eye_L" , s = True , d = False , type = "animCurve" , shapes = True )
	if (tempString):
		cmds.delete( tempString )
	# 头
	# if autoHead:
	tempString = cmds.listConnections( nameSpace + "FKHead_M" , s = True , d = False , type = "animCurve" )
	if (tempString):
		cmds.delete( tempString )

	# if autoBlink:
	tempString = cmds.listConnections( nameSpace + "ctrlEye_R" , nameSpace + "ctrlEye_L" , s = True , d = False , type = "animCurve" , shapes = True )
	if tempString:
		cmds.delete( tempString )
	# 接触眼睛跟随
	# if autoHead:
	cmds.setAttr( nameSpace + "AimEye_M.follow" , 0 )
	import random
	nextBlinkTriggFrameNr = keyTimes [0] + random.randint( 25.0 , 40.0 )
	nextGlipseTriggFrameNr = keyTimes [0] + random.randint( 25.0 , 40.0 )
	nextHeadTriggFrameNr = keyTimes [0] + random.randint( 80.0 , 100.0 )
	for i in range( 1 , int( cmds.playbackOptions( q = True , max = True ) ) ):
		if i < keyTimes [0]:
			continue
		# if autoBlink and i == nextBlinkTriggFrameNr:
		if i == nextBlinkTriggFrameNr:
			nextBlinkTriggFrameNr = i + random.uniform( 50.0 , 250.0 )
			cmds.setKeyframe( nameSpace + "ctrlEye_R" , nameSpace + "ctrlEye_L" , at = ("blink") , t = i , v = 1.5 )
			cmds.setKeyframe( nameSpace + "ctrlEye_R" , nameSpace + "ctrlEye_L" , at = ("blink") , t = (i + 1) , v = 10 )
			cmds.setKeyframe( nameSpace + "ctrlEye_R" , nameSpace + "ctrlEye_L" , at = ("blink") , t = (i + 3) , v = 10 )
			cmds.setKeyframe( nameSpace + "ctrlEye_R" , nameSpace + "ctrlEye_L" , at = ("blink") , t = (i + 6) , v = 1.5 )
			cmds.setKeyframe( nameSpace + "ctrlEye_R" , nameSpace + "ctrlEye_L" , at = ("blink") , t = i + ((nextBlinkTriggFrameNr - i) * 1 / 4) , v = 2.5 )
			cmds.setKeyframe( nameSpace + "ctrlEye_R" , nameSpace + "ctrlEye_L" , at = ("blink") , t = i + ((nextBlinkTriggFrameNr - i) * 3.8 / 4) , v = 2.5 )
			# squint
			tempFloat = random.uniform( 1.0 , 5.0 )
			cmds.setKeyframe( nameSpace + "ctrlEye_R" , nameSpace + "ctrlEye_L" , at = "squint" , t = i + ((nextBlinkTriggFrameNr - i) * 1.5 / 4) , v = 0 )
			cmds.setKeyframe( nameSpace + "ctrlEye_R" , nameSpace + "ctrlEye_L" , at = "squint" , t = i + ((nextBlinkTriggFrameNr - i) * 2 / 4) , v = tempFloat )
			cmds.setKeyframe( nameSpace + "ctrlEye_R" , nameSpace + "ctrlEye_L" , at = "squint" , t = i + ((nextBlinkTriggFrameNr - i) * 3.8 / 4) , v = tempFloat )
			cmds.setKeyframe( nameSpace + "ctrlEye_R" , nameSpace + "ctrlEye_L" , at = "squint" , t = i + ((nextBlinkTriggFrameNr - i) * 4 / 4) , v = 0 )

		# if autoGlimpse and i == nextGlipseTriggFrameNr:
		if i == nextGlipseTriggFrameNr:
			nextGlipseTriggFrameNr = i + random.uniform( 50.0 , 200.0 )
			cmds.setKeyframe( (nameSpace + "Eye_L.ry") , (nameSpace + "Eye_R.ry") , (nameSpace + "Eye_L.rx") , (nameSpace + "Eye_R.rx") , t = i , v = 0 )
			tempFloat0 = random.uniform( -1.0 , 1.0 )
			tempFloat1 = random.uniform( -6.0 , 6.0 )
			cmds.setKeyframe( nameSpace + "Eye_L.rx" , nameSpace + "Eye_R.rx" , t = i + 10 , v = tempFloat0 )
			cmds.setKeyframe( nameSpace + "Eye_L.ry" , nameSpace + "Eye_R.ry" , t = i + 10 , v = tempFloat1 )
			cmds.setKeyframe( nameSpace + "Eye_L.rx" , nameSpace + "Eye_R.rx" , t = i + 15 , v = tempFloat0 )
			cmds.setKeyframe( nameSpace + "Eye_L.ry" , nameSpace + "Eye_R.ry" , t = i + 15 , v = tempFloat1 )
			cmds.setKeyframe( nameSpace + "Eye_L.ry" , nameSpace + "Eye_R.ry" , (nameSpace + "Eye_L.rx") , (nameSpace + "Eye_R.rx") , t = i + 20 , v = 0 )
			cmds.setKeyframe( nameSpace + "Eye_L.ry" , nameSpace + "Eye_R.ry" , (nameSpace + "Eye_L.rx") , (nameSpace + "Eye_R.rx") , t = i + 25 , v = 0 )
			tempFloat0 = random.uniform( -1.0 , 1.0 )
			tempFloat1 = random.uniform( -6.0 , 6.0 )
			cmds.setKeyframe( nameSpace + "Eye_L.rx" , nameSpace + "Eye_R.rx" , t = i + 30 , v = tempFloat0 , at = "rx" )
			cmds.setKeyframe( nameSpace + "Eye_L.ry" , nameSpace + "Eye_R.ry" , t = i + 30 , v = tempFloat1 , at = "ry" )
			cmds.setKeyframe( nameSpace + "Eye_L.rx" , nameSpace + "Eye_R.rx" , t = i + 38 , v = tempFloat0 , at = "rx" )
			cmds.setKeyframe( nameSpace + "Eye_L.ry" , nameSpace + "Eye_R.ry" , t = i + 38 , v = tempFloat1 , at = "ry" )
			cmds.setKeyframe( nameSpace + "Eye_L.ry" , nameSpace + "Eye_R.ry" , nameSpace + "Eye_L.rx" , nameSpace + "Eye_R.rx" , t = i + 41 , v = 0 )
		# if autoHead and i == nextHeadTriggFrameNr:
		if i == nextHeadTriggFrameNr:
			nextHeadTriggFrameNr = i + random.uniform( 25.0 , 300.0 )
			moveDur = random.uniform( 5.0 , 20.0 )
			tempFloat = cmds.getAttr( nameSpace + "FKHead_M.r" , t = i )
			cmds.setKeyframe( nameSpace + "FKHead_M.rx" , t = i , v = tempFloat [0] [0] )
			cmds.setKeyframe( nameSpace + "FKHead_M.ry" , t = i , v = tempFloat [0] [1] )
			cmds.setKeyframe( nameSpace + "FKHead_M.rz" , t = i , v = tempFloat [0] [2] )
			cmds.setKeyframe( nameSpace + "FKHead_M.rz" , t = i + (moveDur / 2.0) , v = (tempFloat [0] [2] - 4) )
			cmds.setKeyframe( nameSpace + "FKHead_M.rx" , t = i + moveDur , v = random.uniform( -8.0 , 8.0 ) )
			cmds.setKeyframe( nameSpace + "FKHead_M.ry" , t = i + moveDur , v = random.uniform( -4.0 , 4.0 ) )
			cmds.setKeyframe( nameSpace + "FKHead_M.rz" , t = i + moveDur , v = random.uniform( -2.0 , 2.0 ) )
			# if autoEyeBrows:

			tempFloat = cmds.getAttr( nameSpace + "ctrlBrow_R.t" , t = i )
			cmds.setKeyframe( nameSpace + "ctrlBrow_R.tx" , nameSpace + "ctrlBrow_L.tx" , t = i + (moveDur / 2.0) , v = tempFloat [0] [0] )
			cmds.setKeyframe( nameSpace + "ctrlBrow_R.ty" , nameSpace + "ctrlBrow_L.ty" , t = i + (moveDur / 2.0) , v = tempFloat [0] [1] )
			cmds.setKeyframe( nameSpace + "ctrlBrow_R.tx" , nameSpace + "ctrlBrow_L.tx" , t = i + moveDur , v = random.uniform( -0.8 , 0.8 ) )
			cmds.setKeyframe( nameSpace + "ctrlBrow_R.ty" , nameSpace + "ctrlBrow_L.ty" , t = i + moveDur , v = random.uniform( -0.8 , 0.8 ) )

	if segmentReplacing:
		cmds.setAttr( nameSpace + "subTitlesBox.sx" , 4 )
	cmds.select( nameSpace + "subTitles" , r = 1 )
	cmds.dgdirty( a = True )

	selected_objects = [nameSpace + "ctrlBrow_R" , nameSpace + "ctrlBrow_L" , nameSpace + "ctrlPhonemes_M" , nameSpace + "FKHead_M" , nameSpace + "Eye_L" , nameSpace + "Eye_R" , nameSpace + "ctrlEye_R" , nameSpace + "ctrlEye_L"]
	for obj in selected_objects:
		anim_curves = cmds.listConnections( obj , type = 'animCurve' , destination = 0 )  # 获取与物体关联的动画曲线
		if anim_curves:
			for each in anim_curves:
				cmds.keyframe( each , edit = True , relative = True , timeChange = -1 )
	Timeline_startFrame = cmds.playbackOptions( q = True , min = True )
	Timeline_endFrame = cmds.playbackOptions( q = True , max = True )
	cmds.bakeResults( selected_objects , t = (Timeline_startFrame , Timeline_endFrame) , sb = 1 )
	cmds.filterCurve( selected_objects , f = "simplify" , timeTolerance = 0.01 )


def asAutoLipSyncPhonemeMapping ( phone ):
	phone = phone.upper()
	phoneme = ""
	if phone == "EY1":
		phoneme = "aaa"
	if phone == "Z":
		phoneme = "sss"
	if phone == "B":
		phoneme = "mbp"
	if phone == "AA2":
		phoneme = "aaa"
	if phone == "D":
		phoneme = "lntd"
	if phone == "IY0":
		phoneme = "tth"
	if phone == "K":
		phoneme = "gk"
	if phone == "AO2":
		phoneme = "ohh"
	if phone == "R":
		phoneme = "rrr"
	if phone == "T":
		phoneme = "lntd"
	if phone == "G":
		phoneme = "gk"
	if phone == "AH0":
		phoneme = "ahh"
	if phone == "OY1":
		phoneme = "ohh"
	if phone == "N":
		phoneme = "lntd"
	if phone == "L":
		phoneme = "lntd"
	if phone == "M":
		phoneme = "mbp"
	if phone == "AY1":
		phoneme = "ahh"
	if phone == "OW2":
		phoneme = "ohh"
	if phone == "S":
		phoneme = "sss"
	if phone == "P":
		phoneme = "mbp"
	if phone == "EH2":
		phoneme = "eh"
	if phone == "IY1":
		phoneme = "iee"
	if phone == "AY2":
		phoneme = "aaa"
	if phone == "OW1":
		phoneme = "ohh"
	if phone == "ER0":
		phoneme = "schwa"
	if phone == "UW1":
		phoneme = "ohh"
	if phone == "W":
		phoneme = "www"
	if phone == "DH":
		phoneme = "lntd"
	if phone == "JH":
		phoneme = "ssh"
	if phone == "IH1":
		phoneme = "iee"
	if phone == "IH0":
		phoneme = "iee"
	if phone == "NG":
		phoneme = "gk"
	if phone == "IH2":
		phoneme = "eh"
	if phone == "V":
		phoneme = "schwa"
	if phone == "AA1":
		phoneme = "ohh"
	if phone == "TH":
		phoneme = "lntd"
	if phone == "ZH":
		phoneme = "ssh"
	if phone == "AE2":
		phoneme = "aaa"
	if phone == "SH":
		phoneme = "ssh"
	if phone == "EH1":
		phoneme = "eh"
	if phone == "AA0":
		phoneme = "aaa"
	if phone == "F":
		phoneme = "fff"
	if phone == "AW1":
		phoneme = "www"
	if phone == "AE1":
		phoneme = "aaa"
	if phone == "OW0":
		phoneme = "ohh"
	if phone == "AW2":
		phoneme = "aaa"
	if phone == "EY2":
		phoneme = "eh"
	if phone == "EY0":
		phoneme = "aaa"
	if phone == "AE0":
		phoneme = "aaa"
	if phone == "IY2":
		phoneme = "iee"
	if phone == "CH":
		phoneme = "ssh"
	if phone == "ER1":
		phoneme = "ahh"
	if phone == "EH0":
		phoneme = "ahh"
	if phone == "UW2":
		phoneme = "ohh"
	if phone == "AH1":
		phoneme = "ohh"
	if phone == "HH":
		phoneme = "schwa"
	if phone == "AH2":
		phoneme = "ahh"
	if phone == "AO0":
		phoneme = "ahh"
	if phone == "OY2":
		phoneme = "ohh"
	if phone == "OY0":
		phoneme = "ohh"
	if phone == "UH1":
		phoneme = "ohh"
	if phone == "AO1":
		phoneme = "ohh"
	if phone == "UW0":
		phoneme = "ohh"
	if phone == "Y":
		phoneme = "uuu"
	if phone == "AW0":
		phoneme = "aaa"
	if phone == "AY0":
		phoneme = "ahh"
	if phone == "ER2":
		phoneme = "ohh"
	if phone == "UH0":
		phoneme = "uuu"
	if phone == "UH2":
		phoneme = "ohh"
	return phoneme


nameSpace = "A10_C0350WJY_RIG:"
asAutoLipSyncForceAlign( nameSpace )
